package com.google.masai;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import android.app.Activity;
import android.content.SharedPreferences;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.dropbox.client.DropboxAPI;
import com.dropbox.client.DropboxAPI.Config;
import com.dropbox.client.DropboxAPI.Entry;
import com.dropbox.client.DropboxAPI.FileDownload;

public class DropBox {

    final static private String CONSUMER_KEY = "1ulu2y4f1e4cuon";
    final static private String CONSUMER_SECRET = "9a1hxrnd9zolyo1";

    private DropboxAPI api;

    final static public String ACCOUNT_PREFS_NAME = "prefs";
    final static public String ACCESS_KEY_NAME = "ACCESS_KEY";
    final static public String ACCESS_SECRET_NAME = "ACCESS_SECRET";
    
    private String username;
    private String password;
    
    private boolean mLoggedIn;
    private EditText mLoginEmail;
    private EditText mLoginPassword;
    private Button mSubmit;
    private TextView mText;
    private Config mConfig;
   	private DropboxAPI.Account mAccount;
   	private String[] keys;
    
    
	/**
	 * Connects to Dropbox Service using username and password
	 * 
	 * @param username - Username of dropbox account
	 * @param password - password of dropbox account
	 */
	public DropBox(String username, String password){
		api = new DropboxAPI();
		getConfig(); // get configuration and set mConfig
		 
		this.username = username;
		this.password = password; 
		
		keys = authenticateWithCred(username, password) ;
		
	}
	
	/**
	 * Connects to Dropbox service with the secret token
	 * @param keys a String array with access key and access secret in that order
	 * @throws Exception
	 */
	public DropBox (String[] keys) throws Exception{
		// Check that only valid keys is given
		if(keys.length !=2){
			throw new Exception("Invalid Key Pair specified");
		}
		
		// get and set the configuration
		api = new DropboxAPI(); 
		getConfig(); 
		
		
		// make the call to authenticate with web service
		boolean success = authenticateWithKeys(keys);
		
	}
	
	
	
	/**
	 * Returns all files of the given folder in DropBox as Entry objects in 
	 * an array list 
	 * @param path - should start with "/". An example path is  "/public"
	 * @return
	 */
	public ArrayList<Entry> getFiles(String path){
		
		Entry entry = api.metadata("dropbox", path, 0, null, true);
		ArrayList<Entry> list = (!entry.is_dir) ? null : entry.contents ;
		
		return list; 
	}
	/**
	 * 
	 * @param file - Java File object to upload
	 * @param path - path on dropbox to save the file. It should start with "/"
	 */
	public void uploadFile(File file, String path){
		
		if(!file.exists()){
			Log.d("DROPBOX", "ERROR Upload Operation stopped - File not found: " + file);
			return;
		}
		
		
		Entry e = api.createFolder("dropbox", "getit");
		
		int result = api.putFile("dropbox", path, file);
		
	}
	
	
	
	
	/**
	 * Uploads file to the public folder of Dropbox
	 * @param file - Java File object to upload
	 * @param path - path on dropbox to save the file. It should start with "/"
	 */
	public void uploadFilePublic(File file){
		
		if(!file.exists()){
			
		}
		
		
		Entry e = api.createFolder("dropbox", "getit");
		String path = "/public";
		
		int result = api.putFile("dropbox", path, file);
		
	}

	
	/**
	 * 
	 * @param dbPath - FilePath of Dropbox file to download. It should start with "/"
	 * @param localFile - The file localfile to save a copy of the downloaded file to. We create the file if it doesn't exist yet. 
	 * @return true on success
	 * @throws IOException if an error occurs. 
	 */
	public boolean downloadDropboxFile(String dbPath, File localFile) throws IOException{

	    BufferedInputStream br = null;
	    BufferedOutputStream bw = null;

	    try {
	        if (!localFile.exists()) {
	            localFile.createNewFile(); //otherwise dropbox client will fail silently
	        }

	        FileDownload fd = api.getFileStream("dropbox", dbPath, null);
	        br = new BufferedInputStream(fd.is);
	        bw = new BufferedOutputStream(new FileOutputStream(localFile));

	        byte[] buffer = new byte[4096];
	        int read;
	        while (true) {
	        read = br.read(buffer);
	        if (read <= 0) {
	        break;
	        }
	        bw.write(buffer, 0, read);
	        }
	    } finally {
	        //in finally block:
	        if (bw != null) {
	            bw.close();
	        }
	        if (br != null) {
	            br.close();
	        }
	    }
	    
	    return true;
	}
	
	public String[] getStoredTokens(){
		return keys; 
	}
	
	/**
	 * 
	 * @param user
	 * @param pass
	 * @return access tokens. Null indicates an error condition occurred
	 */
	public String[] authenticateWithCred(String user, String pass){
		
		mConfig= api.authenticate(mConfig, user, pass);
		
		int success = mConfig.authStatus; 
		
		if(success != DropboxAPI.STATUS_SUCCESS){ // if the auth failed
			return null; // 
		}
		
		mAccount = api.accountInfo(); 
		if(!mAccount.isError()){ // no errors occurred with logging in
			// Save the auth keys. 
			
			String key = mConfig.accessTokenKey;
			String secret = mConfig.accessTokenSecret;
			String[] keyArray = new String[2];
			
			/* First element should have key and second should have secret  */
			keyArray[0] = key;
			keyArray[1] = secret; 
			
			return keyArray;
			
			
			
		} else{
			String msg = "Account info error: " + mAccount.httpCode + " " + mAccount.httpReason;
			Log.d("DROPBOX TAG", msg);
			return null; // an error occured
		}
		
		
		//return null; // some error occured
		
		
	}
	
	
	/**
	 * Authenticate with dropbox using the already obtained secret key pai
	 * This is the preferred way to authenticate with DropBox. (as opposed to continually
	 * authentiicating with user credentials)
	 * 
	 * @param keys : String array with Access_Key_Name and Access_Secret_Name (in this order)
	 * @return true on success
	 */
	public boolean authenticateWithKeys(String keys[]){
		
		if (keys != null) {
			
	        mConfig = api.authenticateToken(keys[0], keys[1], mConfig);
	        if (mConfig != null) { // if we authenticated
	            
	        	this.keys = keys;  // save a copy of the keys
	        	return true;
	        }
	        
    	}
		
		return false ; // it failed (i'm asssuming this here - it's not clear from dropbox api docs)  
	}
	
	
	public DropboxAPI getAPI(){
		return api; 
	}
	

	
	protected Config getConfig() {
    	if (mConfig == null) {
	    	mConfig = api.getConfig(null, false);
	    	// TODO On a production app which you distribute, your consumer
	    	// key and secret should be obfuscated somehow.
	    	mConfig.consumerKey=CONSUMER_KEY;
	    	mConfig.consumerSecret=CONSUMER_SECRET;
	    	mConfig.server="api.dropbox.com";
	    	mConfig.contentServer="api-content.dropbox.com";
	    	mConfig.port=80;
    	}
    	return mConfig;
    }
    
	
    /**
     * Shows keeping the access keys returned from Trusted Authenticator in a local
     * store, rather than storing user name & password, and re-authenticating each
     * time (which is not to be done, ever).
     * 
     * @return Array of [access_key, access_secret], or null if none stored
     */
    public String[] getKeys(Activity act) {
        SharedPreferences prefs = act.getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
        String key = prefs.getString(ACCESS_KEY_NAME, null);
        String secret = prefs.getString(ACCESS_SECRET_NAME, null);
        if (key != null && secret != null) {
        	String[] ret = new String[2];
        	ret[0] = key;
        	ret[1] = secret;
        	return ret;
        } else {
        	return null;
        }
    }
    
	
	
	
}
